#pragma once

// 接收/响应http的GET/POST请求
// 分析http请求 
// 处理http请求 
// 分析：类似序列化的过程

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <sys/wait.h>

#include "log.hpp"
#include "read_one_line.hpp"

#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define PAGE_404 "404.html" 

#define OK 200 
// 空行
#define LINE_END "\r\n" 
#define SEP ": "  // 注意是“: ”不是 “:”
#define BAD_REQUEST 400
#define NOT_FOUND 404 
#define SERVER_ERROR 500 

#define DEBUG

//
static std::string statusCodeExplain(int code)
{
    std::string explain ;
    switch (code)
    {
    case 200:
        explain = "OK";
        break;
    case 404:
        explain = "NOT Found";
        break;
    default:
        break;
    }
    return explain ; 
}

static std::string suffixToMimeType(std::string suffix)
{
    static std::unordered_map<std::string, std::string> transition 
    {
        {".html", "text/html"},
        {".htx", "text/html"},
        {".jpg", "application/x-jpg"},
        {".apk", "application/vnd.android.package-archive"},
        {".exe", "application/x-msdownload"}
    };

    auto iter = transition.find(suffix);
    if(iter != transition.end())
    {
        return iter->second ;
    }
    return "text/html" ;
}



class HttpReuqest
{
    public:
        //初步接收：
        //请求首行
        std::string _request_line ; 
        //header部分
        std::vector<std::string> _request_header ;  
        //空行
        std::string _blank ; 
        // 请求正文
        std::string _request_body ; 

        //进一步拆分、解析，便于交付处理
        //请求方法
        std::string _method;
        //请求参数 / 无参 
        std::string _url ;
        //请求版本
        std::string _version ; 
        //将header部分以kv形式存储
        std::unordered_map<std::string, std::string> _header_kv ; 
        //正文长度
        int _content_length ;
        std::string _path ; 
        std::string _suffix ;
        std::string _query_string ;  //请求参数

        //CGI模式标记位
        //GET方法且有参数、POST方法、访问的资源为可执行文件三种情况设置为cgi模式
        bool _cgi ; 
        int  _size ;//存储返回资源的长度

    public:
        HttpReuqest()
        :_content_length(0)
        ,_cgi(false)
        {

        }

        ~HttpReuqest()
        {
            
        }

};

class HttpResponse
{
    public:
        std::string _status_line;
        std::vector<std::string> _header_response;
        std::string _biank ; 
        std::string _response_body ;

        //状态码
        int _status_code ;
        //？？？ 
        int _fd ; 
    public:
        HttpResponse()
        :_biank(LINE_END)
        ,_status_code(OK)
        {

        }

        ~HttpResponse()
        {

        }
};



//请求处理
class DemandProcessing
{
    private:
        int _sock ; 
        HttpResponse _http_response;
        HttpReuqest  _http_request ;
        //???
        bool _stop ; 
    
    private:

        //接收首行请求
        bool recvHttpRequestLine()
        {
            std::string& line = _http_request._request_line ; 
            if( 0 < Util::readOneLine(_sock, line) )
            {
                //取掉换行符
                line.resize(line.size() - 1 ) ;
                LOG(INFO, "recv reuqest: " + line); 
            }
            else
            {
                _stop = true ; 
            }
            //std::cout << line ; 
            std::cout << "RecvHttpRequestLine: " << _stop << std::endl ; 
            return _stop ; 
        }

        bool recvHttpRequestHeader()
        {
            std::string line ; 
            while(true)
            {
                line.clear();    
                if(0 >= Util::readOneLine(_sock, line)) 
                {
                    _stop = true ; 
                    break; 
                }
                if(line == "\n")
                {
                    _http_request._blank = line ; 
                    break; 
                }

                line.resize(line.size() - 1); //去掉换行符 
                LOG(INFO, "recv request header:" + line); 
                _http_request._request_header.push_back(line);
            }
        }

         void parseHttpRequestLine()
        {
            std::string &line = _http_request._request_line;
            std::stringstream ss(line);
            ss >> _http_request._method 
            >> _http_request._url
            >> _http_request._version ;
            

        }
        
        void parseHttpRequestHeader()
        {
            std::string key ;
            std::string value ; 
            for(auto& temp_header : _http_request._request_header)
            {
                if(true == Util::cutString(temp_header, key, value, SEP))
                {
                    _http_request._header_kv.insert({key, value});
                }
            }
        }


        //判断请求是否有正文
        bool isNeedRecvHttpRequestBody()
        {
            std::string method = _http_request._method ; 
            if(method == "POST")
            {
                // 正文body存在时才会出现此header
                auto iter = _http_request._header_kv.find("Content-Length") ; //   —— - —— ？？？
                if(iter != _http_request._header_kv.end())
                {
                    LOG(INFO, "Post Method ———— Content-Length:" + iter->second) ; // ！ ！ ！
                    _http_request._content_length = atoi(iter->second.c_str());
                    return true ; 
                }
            }
            return false ; 
        }

        bool recvHttpRequestBody()
        {
            if(isNeedRecvHttpRequestBody())
            {
                int contene_length = _http_request._content_length ; 
                std::string& body =  _http_request._request_body ;
                char ch = 0 ;

                while(contene_length > 0 ) 
                {
                    ssize_t s = recv(_sock, &ch, 1, 0 );  
                    if(0 < s)
                    {
                        body.push_back(ch);
                        contene_length-- ; 
                    }
                    else if (s == 0)   ////////////////////////////这里似乎有问题
                    {
                        break;
                    }
                    else
                    {
                        _stop = true ; 
                        break ; 
                    }
                } 

                LOG(INFO, "had recv body :" + body) ; // 这里的日志显示没收到信息 
            }
            else
            {
                LOG(INFO, "no HttpRequest Body");
            }

            return _stop ; 
        }

        public: //////////////////////////////// 临时测试

        void recvHttpRequest()
        {
            // 执行顺序不能错 
            if((!recvHttpRequestLine()) && (!recvHttpRequestHeader()))
            {
                parseHttpRequestLine(); 
                if(_stop == false) 
                LOG(INFO, "parseHttpRequestLine success") ;
                parseHttpRequestHeader();
                if(_stop == false) 
                LOG(INFO, "parseHttpRequestHeader success") ;
                recvHttpRequestBody();
                if(_stop == false) 
                LOG(INFO, "recvHttpRequestBody success") ;
            }
        }

        private : /////////////////////////////  临时测试

    
        public  :
        // 命名为buildHttpResponseLine更合理？
        // 对请求做初步的处理
        // 构建响应 , 初始化Response _http_response ;
        // 设置 _http_response 状态码 
        void buildHttpResponse()
        {
            std::string _path ; 
            struct stat st ;   
            std::size_t found = 0 ; 
            auto& code = _http_response._status_code ;           

            if(_http_request._method != "POST" && _http_request._method != "GET")
            {
                //非法请求
                LOG(WARNING, _http_request._method + "—— method not right") ;
                code = BAD_REQUEST ; 
                goto END ; 
              
            }
            else if(_http_request._method == "GET")
            {
                //GET请求的处理
                //GET方法，url以？分隔参数               
                size_t pos = _http_request._url.find("?"); 
                if(pos != std::string::npos )
                {
                    Util::cutString(_http_request._url, _http_request._path, _http_request._query_string, "?");
                    _http_request._cgi = true ; 
                }
                else
                {
                    _http_request._path = _http_request._url;
                }
            }
            else if(_http_request._method == "POST")
            {
                //POST请求的处理
                // ? ? ? ? ? post请求必定是cgi模式？
                _http_request._cgi = true ;
                _http_request._path = _http_request._url ;  
            }
            else
            {
                //意外  
            }

            //_http_request._path = WEB_ROOT + _http_request._path ;
            _path = _http_request._path ; 
            _http_request._path = WEB_ROOT ;
            _http_request._path += _path ; 
            
            //请求的路径为一个目录时，自将其路径转化为该目录的默认首页
            if(_http_request._path[_http_request._path.size() - 1] == '/') // !!!
            {
                _http_request._path = _http_request._path + HOME_PAGE ; 
            }

            //stat函数失败，找不到指定文件，设置错误码。执行成功返回0
            if(stat(_http_request._path.c_str(), &st) == 0 )
            {
                if(S_ISDIR(st.st_mode))
                {
                    //为一个目录
                    _http_request._path = _http_request._path + "/" + WEB_ROOT ;
                    stat(_http_request._path.c_str(), &st); 
                }

                //如过访问的文件为可执行文件需要做特殊处理
                if((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) )
                {
                    _http_request._cgi = true ;  
                }

            }
            else
            {  //请求资源不存在
                LOG(WARNING, _http_request._path + "Not Found");
                code = NOT_FOUND ;
                goto END ; 
            }

            //请求路径没给请求资源的文件后缀默认为.html给了就按请求的后缀设置
            found = _http_request._path.rfind(".") ; 
            if(found == std::string::npos)
            {
                _http_request._suffix = ".html" ; 
            }
            else
            {
                _http_request._suffix = _http_request._path.substr(found);
            }

            if(_http_request._cgi == true)
            {
                code = processCgi();
            }
            else
            {
                code = processNoCgi();
            }
            

        END :
            buildHttpResponseHelper();
           
        }//函数的括号

        private :

        //命名为buildHttpResponseHeader更合理？
        //根据buildHttpResponse函数处理的_http_request的结果初始化_http_response
        void buildHttpResponseHelper()
        {   
            int& code =  _http_response._status_code ; 
            std::string& status_line = _http_response._status_line ; 

            //首行
            status_line += HTTP_VERSION ;
            status_line += " ";
            status_line += std::to_string(code);
            status_line += " ";
            status_line += statusCodeExplain(code);
            status_line += LINE_END ; 

            //根据请求情况构建其余Header和Body
            std::string path = WEB_ROOT ; 
            path += "/" ; 
            switch (code)
            {
            case OK:
                buildOkResponseHeader();
                break;
            case NOT_FOUND:
                path += PAGE_404 ; 
                buildErrorResponseHeader(path);
                break;
            case BAD_REQUEST:
                path += PAGE_404 ; 
                buildErrorResponseHeader(path);
                break;
            case SERVER_ERROR:
                path += PAGE_404 ; 
                buildErrorResponseHeader(path);
                break;

            default:
                break;
            }

        }


        void buildOkResponseHeader()
        {
            std::string line = "Content-Type: ";
            line += suffixToMimeType(_http_request._suffix) ;
            line += LINE_END ; 
            _http_response._header_response.push_back(line);

            line = "Content-Length: ";
            if(true == _http_request._cgi)
            {
                line += std::to_string(_http_response._response_body.size());
            }
            else
            {
                // GET方法且无参 
                _http_request._size ;
                line += std::to_string(_http_request._size) ; 
            }
            line += LINE_END ; 
            _http_response._header_response.push_back(line) ;

        }

        private:

        //应该命名为buildErrorResponse
        void buildErrorResponseHeader(std::string page_path)
        {
            _http_request._cgi = false ;
            _http_response._fd = open(page_path.c_str(), O_RDONLY);
            if(_http_response._fd > 0)
            {
                struct stat st ;
                stat(page_path.c_str(), &st); 
                _http_request._size = st.st_size ; 

                std::string line =  "Content-Type: text/html";
                line += LINE_END ;
                _http_response._header_response.push_back(line) ; 

                line = "Content-Length: " ;
                line +=  std::to_string( _http_request._size ) ; 
                line += LINE_END ; 
                _http_response._header_response.push_back(line) ; 
            }
            else
            {
                LOG(WARNING, "error request tagert inexistence ") ;
            }
        }

        public: 
        void sentHttpResponse()
        {
            send(_sock, _http_response._status_line.c_str(), _http_response._status_line.size(), 0);
            for(auto& tem : _http_response._header_response)
            {
                send(_sock, tem.c_str(), tem.size(), 0 );
            }
            send(_sock, _http_response._biank.c_str(), _http_response._biank.size(), 0 );

            if(true == _http_request._cgi) 
            {
                
            }
            else
            {
                LOG(INFO, "had send response :" + _http_request._path );
                sendfile(_sock, _http_response._fd, NULL, _http_request._size);
                // 关闭操作交给http_Server?
                //lose(_http_response._fd);
            }
        }

        private:
        //返回状态码
        int processCgi()
        {
            LOG(INFO, "cgi method runing ……");
            int code = OK ;

            std::string& method = _http_request._method ;
            std::string& query_string = _http_request._query_string ;
            std::string& body_text = _http_request._request_body ; 
            std::string& bin = _http_request._path;
            std::string& resonse_body = _http_response._response_body;
            int content_length = _http_request._content_length;

            //通过环境变量传到替换的进程里
            std::string query_string_env ; 
            std::string method_env ;
            std::string content_length_env ;

            int input[2] ;
            int output[2] ;

            if(pipe(input) < 0)
            {
                LOG(ERROR, "input pipe create faild") ;
                code = SERVER_ERROR ;
                return code;
            }

            if(pipe(output) < 0)
            {
                close(input[0]);
                close(input[1]);
                LOG(ERROR, "output pipe create faild"); 
                code = SERVER_ERROR ;
                return SERVER_ERROR ;
            }


            pid_t new_pid = fork() ;
            if(new_pid > 0)
            {  //parent  接收处理结果
                close(input[1]);
                close(output[0]);

                //debug
                LOG(INFO, "parent get method :" + method);

                if(method == "POST")
                {
                    const char* strat = body_text.c_str() ;
                    int total = 0 ; //发送的总长度 
                    int size = 0 ;  //一次发送的长度 
                    while (total < content_length)    
                    {
                        size = write(output[1], strat + total, (content_length - total)) ;
                        if(size <= 0 )
                        {
                            LOG(ERROR, "write error") ; 
                            break;
                        }
                        total += size ;
                    }
                }

                char ch = 0 ; 
                while (0 > (read(input[1], &ch, 1)))
                {
                    resonse_body.push_back(ch) ; 
                }

                //存储进程退出码
                int status = 0 ; 
                pid_t ret = waitpid(new_pid, &status, 0);
                if(ret == new_pid)
                {
                    if(WIFEXITED(status))
                    {
                        if(WEXITSTATUS(status) == 0)
                        {
                            code = OK ;
                        }
                        else
                        {
                            code = BAD_REQUEST ; 
                        }
                    }
                    else
                    {
                        code = SERVER_ERROR ; 
                    }
                }
                    
                close(input[0]) ;
                close(input[1]) ;
                
                return code ;
            }
            else if (new_pid == 0)
            {   //child 处理请求
                close(input[0]);
                close(output[1]); 

                //debug
                LOG(INFO, "child get method :" + method);

                //环境变量以键值形式存在
                method_env ="METHOD=";
                method_env += method ;
                ////////////////////////////////////////////////////
                putenv((char*)method_env.c_str());
                
                if(method == "GET")
                {
                    query_string_env = "QUERY_STRING=" ;
                    query_string_env += query_string ; 
                    putenv((char*)query_string_env.c_str()) ;
                    LOG(INFO, "GET method set env:" + query_string_env );
#ifdef DEBUG
                    std::cout << "debug:"  << getenv("QUERY_STRING") << std::endl ;
#endif 
                }
                else if(method == "POST")
                {
                    // POST方法的参数包含在body中
                    content_length_env = "CONTENT_LENGTH=" ;
                    content_length_env += std::to_string( content_length ); 
                    putenv((char*)content_length_env.c_str());
                    LOG(INFO, "POST method set env:" + content_length_env);
#ifdef DEBUG
                    std::cout << "debug: "  << getenv("CONTENT_LENGTH") << std::endl ;
#endif 
                }
                else
                {
                    //
                }

                //debug 
                LOG(INFO,"execl will begin————method:" + method + "bin:" + bin + "method_env:" + method_env ) ;

                //重定向 ！！！！！！！！！！！！！！！！！！！！！！！！！！
                dup2(output[0], 0);
                dup2(input[1], 1);

                //进程替换
                //路径 / 命令行参数  / 参数结束标识符nullptr
                //+ "query_string_env:" + query_string_env + "content_length_env" + content_length_env ); 

                execl(bin.c_str(), bin.c_str(), nullptr) ;

                LOG(ERROR, "execl failed ") ; 
                exit(1);
                
            }
            else 
            { // error

            }
            
        }

        
        int processNoCgi()
        {
            _http_response._fd = open(_http_request._path.c_str(), O_RDONLY) ;
            if(0 <= _http_response._fd )
            {
                LOG(INFO, "process no cgi mthod opne :" + _http_request._path + "success" );
                return OK ;
            }

            return  NOT_FOUND ;
        }
    

    public:
        
        DemandProcessing(int sock)
            :_sock(sock)
            ,_stop(false)
        {

        }

        ~DemandProcessing()
        {
            // 线程会共享文件描述符资源，添加了epoll之后，连接的关闭归httpserver所管理，所以这里的文件描述符
           // close(_sock) ; 
        }

        bool isStop()
        {
            return _stop ; 
        }

         //临时测试 
        void temp_test()
        {

            std::cout << "———————————————————temproray_test—————————————————————————" << std::endl 
            << _http_request._method << std::endl 
            << _http_request._request_line <<std::endl 
            << _http_request._request_header[0]
            << "path:"<< _http_request._path << std::endl ; 
            std::cout << "———————————————————temproray_test—————————————————————————" << std::endl ;
        }

};


class CalBack
{
    public:
    CalBack()
    {

    }

    ~CalBack()
    {
        
    }

    void operator()(int sock)
    {
        HandlerRequest(sock) ; 
    }

    void HandlerRequest(int sock)
    {
        LOG(INFO, "Tast HandlerRequest Begin") ;
        
#ifdef DEBUG 

        // 接收整个http请求
        //char buffer[4096] = {0} ;
        //recv(sock, buffer, sizeof(buffer), 0);
        //std::cout << "__________________________________________" << std::endl ;
        //std::cout << buffer << std::endl ; 
        //std::cout << "__________________________________________" << std::endl ;

#endif

        DemandProcessing *dp = new DemandProcessing(sock) ; 
        dp->recvHttpRequest(); 
        if(dp->isStop() == false)
        {
            dp->buildHttpResponse();
            LOG(INFO, "Response is read , will send, witch fd is" + std::to_string(sock)) ; 
            dp->sentHttpResponse();
        }
        else
        {
            LOG(WARNING, "recv error ") ;
        }

        delete dp ; 

        LOG(INFO, "Hander Request End") ;
    }


};
